﻿using Geotools.Geometries;
using System;

namespace AzukiMap.Tools
{
    public class GeometryUtil : GeometryFactory
    {
        public GeometryUtil()
            : base()
        {
        }

        public GeometryUtil(PrecisionModel precisionModel, int SRID)
            : base(precisionModel, SRID)
        {
        }

        public GTPoint CreatePoint(double x, double y)
        {
            GTCoordinate coord = new GTCoordinate(x, y);
            GTPoint p = this.CreatePoint(coord);
            return p;
        }

        public GTPolygon CreateExtentPolygon(
            double tlX, double tlY, double blX, double blY,
            double brX, double brY, double trX, double trY)
        {
            GTCoordinates coords = new GTCoordinates();
            coords.Add(new GTCoordinate(tlX, tlY));
            coords.Add(new GTCoordinate(blX, blY));
            coords.Add(new GTCoordinate(brX, brY));
            coords.Add(new GTCoordinate(trX, trY));
            coords.Add(new GTCoordinate(tlX, tlY));
            GTLinearRing shell = this.CreateLinearRing(coords);
            GTPolygon extent = this.CreatePolygon(shell);
            return extent;
        }

        public GTPolygon CreateExtentPolygon(
            double minX, double minY, double maxX, double maxY)
        {
            GTCoordinates coords = new GTCoordinates();
            coords.Add(new GTCoordinate(minX, maxY));
            coords.Add(new GTCoordinate(minX, minY));
            coords.Add(new GTCoordinate(maxX, minY));
            coords.Add(new GTCoordinate(maxX, maxY));
            coords.Add(new GTCoordinate(minX, maxY));
            GTLinearRing shell = this.CreateLinearRing(coords);
            GTPolygon extent = this.CreatePolygon(shell);
            return extent;
        }

        public double GetExtentPolygonWidth(GTPolygon extentPoly)
        {
            GTCoordinate tl = GetExtentPoint(extentPoly, ExtentOrder.TOP_LEFT);
            GTCoordinate tr = GetExtentPoint(extentPoly, ExtentOrder.TOP_RIGHT);
            double tlX = tl.X;
            double tlY = tl.Y;
            double trX = tr.X;
            double trY = tr.Y;
            double width = Math.Sqrt(Math.Pow((trX - tlX), 2) + Math.Pow((trY - tlY), 2));
            return width;
        }

        public double GetExtentPolygonHeight(GTPolygon extentPoly)
        {
            GTCoordinate tl = GetExtentPoint(extentPoly, ExtentOrder.TOP_LEFT);
            GTCoordinate bl = GetExtentPoint(extentPoly, ExtentOrder.BOTTOM_LEFT);
            double tlX = tl.X;
            double tlY = tl.Y;
            double trX = bl.X;
            double trY = bl.Y;
            double height = Math.Sqrt(Math.Pow((trX - tlX), 2) + Math.Pow((trY - tlY), 2));
            return height;
        }

        public double GetPolygonEnvelopeWidth(GTPolygon poly)
        {
            GTEnvelope envelope = poly.GetEnvelopeInternal();
            return envelope.Width;
        }

        /// <summary>
        /// Return a selected position of point from envelope polygon.
        /// </summary>
        /// <param name="extentPoly"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public GTCoordinate GetExtentPoint(GTPolygon extentPoly, ExtentOrder order)
        {
            return extentPoly.GetCoordinates()[(int)order];
        }

        public double[] GetExtentPointsArr(GTPolygon extentPoly)
        {
            double[] points = new double[8];
            GTCoordinate tl = GetExtentPoint(extentPoly, ExtentOrder.TOP_LEFT);
            GTCoordinate bl = GetExtentPoint(extentPoly, ExtentOrder.BOTTOM_LEFT);
            GTCoordinate br = GetExtentPoint(extentPoly, ExtentOrder.BOTTOM_RIGHT);
            GTCoordinate tr = GetExtentPoint(extentPoly, ExtentOrder.TOP_RIGHT);
            points[(int)ExtentArrOrder.TOP_LEFT_X] = tl.X;
            points[(int)ExtentArrOrder.TOP_LEFT_Y] = tl.Y;
            points[(int)ExtentArrOrder.BOTTOM_LEFT_X] = bl.X;
            points[(int)ExtentArrOrder.BOTTOM_LEFT_Y] = bl.Y;
            points[(int)ExtentArrOrder.BOTTOM_RIGHT_X] = br.X;
            points[(int)ExtentArrOrder.BOTTOM_RIGHT_Y] = br.Y;
            points[(int)ExtentArrOrder.TOP_RIGHT_X] = tr.X;
            points[(int)ExtentArrOrder.TOP_RIGHT_Y] = tr.Y;

            return points;
        }

        public GTPoint GetPolygonCenter(GTPolygon extentPolygon)
        {
            GTCoordinates coords = extentPolygon.GetCoordinates();
            double sumX = 0;
            double sumY = 0;
            double centerX = 0;
            double centerY = 0;

            // get sum of x,y. the last point is the same as first point.
            for (int i = 0; i < coords.Count - 1; i++)
            {
                sumX += coords[i].X;
                sumY += coords[i].Y;
            }
            if (sumX != 0)
            {
                centerX = sumX / (coords.Count - 1);
            }
            if (sumY != 0)
            {
                centerY = sumY / (coords.Count - 1);
            }
            return CreatePoint(centerX, centerY);
        }

        public GTPolygon EnvelopeToPolygon(GTEnvelope env)
        {
            GTPolygon poly;
            if (env == null)
            {
                poly = null;
            }
            else
            {
                poly = CreateExtentPolygon(env.MinX, env.MinY, env.MaxX, env.MaxY);
            }
            return poly;
        }
    }
}
